#include "Controller.h"

N2F::Iw3D::Controller::Controller()
{
	this->topScreen = this->screens.end();
	this->isLoaded = false;

	return;
}

N2F::Iw3D::Controller::~Controller()
{
	return;
}

const N2F::Iw3D::ScaleFactor N2F::Iw3D::Controller::getScaleFactor() const
{
	return(this->scaleFactor);
}

void N2F::Iw3D::Controller::setScaleFactor(N2F::Iw3D::ScaleFactor scaleFactor)
{
	this->scaleFactor = scaleFactor;

	return;
}

void N2F::Iw3D::Controller::init()
{
	this->inputState = new InputState();
	this->inputState->pointerIsAvailable = s3ePointerGetInt(S3E_POINTER_AVAILABLE) ? true : false;
	this->inputState->keysAreAvailable = (s3eKeyboardGetInt(S3E_KEYBOARD_HAS_KEYPAD) || s3eKeyboardGetInt(S3E_KEYBOARD_HAS_ALPHA));
	this->inputState->osKeyboardIsAvailable = s3eOSReadStringAvailable() == S3E_TRUE;
	this->inputState->multiTouchAvailable = false;

	if (this->inputState->pointerIsAvailable)
	{
		this->inputState->multiTouchAvailable = s3ePointerGetInt(S3E_POINTER_MULTI_TOUCH_AVAILABLE) ? true : false;

		if (this->inputState->multiTouchAvailable)
		{
			s3ePointerRegister(S3E_POINTER_TOUCH_EVENT, (s3eCallback)N2F::Iw3D::Controller::handleMultiTouchButtonCB, this);
			s3ePointerRegister(S3E_POINTER_TOUCH_MOTION_EVENT, (s3eCallback)N2F::Iw3D::Controller::handleMultiTouchMotionCB, this);
		}
		else
		{
			s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, (s3eCallback)N2F::Iw3D::Controller::handleSingleTouchButtonCB, this);
			s3ePointerRegister(S3E_POINTER_MOTION_EVENT, (s3eCallback)N2F::Iw3D::Controller::handleSingleTouchMotionCB, this);
		}
	}

	for (int i = 0; i <= S3E_POINTER_TOUCH_MAX; i++)
	{
		this->inputDrag[i] = false;
	}

	this->OnInit();

	if (!this->screens.empty())
	{
		for (ScreenListIter it = this->screens.begin(); it != this->screens.end(); ++it)
		{
			(*it).second->init();
		}
	}

	this->isLoaded = true;

	return;
}

void N2F::Iw3D::Controller::touch(InputPoint point)
{
	if (!this->isLoaded)
	{
		return;
	}

	this->OnTouch(point);

	return;
}

void N2F::Iw3D::Controller::key(InputKey key)
{
	if (!this->isLoaded)
	{
		return;
	}

	this->OnKey(key);

	return;
}

void N2F::Iw3D::Controller::update(int64 delta)
{
	this->OnUpdate(delta);

	if (!this->visibleScreens.empty())
	{
		for (ScreenStackIter it = this->visibleScreens.begin(); it != this->visibleScreens.end(); ++it)
		{
			this->screens[(*it)]->update(delta);
		}
	}

	if (this->topScreen != this->screens.end())
	{
		this->topScreen->second->update(delta);
	}

	return;
}

void N2F::Iw3D::Controller::render(int64 delta)
{
	this->OnRender(delta);

	if (s3eKeyboardGetInt(S3E_KEYBOARD_GET_CHAR) == 1)
	{
		s3eWChar ch;
		N2F::Iw3D::InputKey key;

		while ((ch = s3eKeyboardGetChar()) != S3E_WEOF)
		{
			key.ch = ch;
			key.key = static_cast<char>(ch);

			this->key(key);
		}
	}

	if (!this->visibleScreens.empty())
	{
		for (ScreenStackIter it = this->visibleScreens.begin(); it != this->visibleScreens.end(); ++it)
		{
			this->screens[(*it)]->draw(delta);
		}
	}

	if (this->topScreen != this->screens.end())
	{
		this->topScreen->second->draw(delta);
	}

	this->OnPostRender(delta);

	return;
}

void N2F::Iw3D::Controller::kill()
{
	for (ScreenListIter it = this->screens.begin(); it != this->screens.end(); ++it)
	{
		(*it).second->kill();
		delete (*it).second;
		(*it).second = NULL;
	}

	this->visibleScreens.clear();
	this->screens.clear();

	this->OnKill();

	return;
}

void N2F::Iw3D::Controller::OnTouch(InputPoint point)
{
	this->topScreen->second->touch(point);

	return;
}

void N2F::Iw3D::Controller::OnKey(InputKey key)
{
	this->topScreen->second->key(key);

	return;
}

void N2F::Iw3D::Controller::handleMultiTouchButtonCB(s3ePointerTouchEvent *event, void *userData)
{
	N2F::Iw3D::Controller *me = static_cast<N2F::Iw3D::Controller *>(userData);

	me->inputDrag[event->m_TouchID] = (event->m_Pressed == 1) ? true : false;

	InputPoint tmp;
	tmp.isMoving = false;
	tmp.isPressed = (event->m_Pressed == 1) ? true : false;
	tmp.isDragging = me->inputDrag[event->m_TouchID];
	tmp.pointId = event->m_TouchID;
	tmp.x = event->m_x;
	tmp.y = event->m_y;

	me->touch(tmp);

	return;
}

void N2F::Iw3D::Controller::handleMultiTouchMotionCB(s3ePointerTouchMotionEvent *event, void *userData)
{
	N2F::Iw3D::Controller *me = static_cast<N2F::Iw3D::Controller *>(userData);

	InputPoint tmp;
	tmp.isMoving = true;
	tmp.isPressed = true;
	tmp.pointId = event->m_TouchID;
	tmp.isDragging = me->inputDrag[event->m_TouchID];
	tmp.x = event->m_x;
	tmp.y = event->m_y;

	me->touch(tmp);

	return;
}

void N2F::Iw3D::Controller::handleSingleTouchButtonCB(s3ePointerEvent *event, void *userData)
{
	N2F::Iw3D::Controller *me = static_cast<N2F::Iw3D::Controller *>(userData);

	me->inputDrag[0] = (event->m_Pressed == 1) ? true : false;

	InputPoint tmp;
	tmp.isMoving = false;
	tmp.isPressed = (event->m_Pressed == 1) ? true : false;
	tmp.pointId = 0;
	tmp.isDragging = me->inputDrag[0];
	tmp.x = event->m_x;
	tmp.y = event->m_y;

	me->touch(tmp);

	return;
}

void N2F::Iw3D::Controller::handleSingleTouchMotionCB(s3ePointerMotionEvent *event, void *userData)
{
	N2F::Iw3D::Controller *me = static_cast<N2F::Iw3D::Controller *>(userData);

	InputPoint tmp;
	tmp.isMoving = true;
	tmp.isPressed = true;
	tmp.pointId = 0;
	tmp.isDragging = me->inputDrag[0];
	tmp.x = event->m_x;
	tmp.y = event->m_y;

	me->touch(tmp);

	return;
}
